#ifndef __UTILS_H__
#define __UTILS_H__

#include <string>
#include <vector>
#include <list>
#include <nlohmann/json.hpp>

#define BIT(X) (1 << X)

union Byte8Data
{
    char buff[8];
    int64_t int64_value;
    uint64_t uint64_value;
    double double_value;
    struct
    {
        int32_t a;
        int32_t b;
    };

    struct
    {
        int16_t aa;
        int16_t ab;
        int16_t ba;
        int16_t bb;
    };
};

union Byte4Data
{
    char buff[4];
    int32_t int32_value;
    uint32_t uint32_value;
    float float_value;
    struct
    {
        int16_t a;
        int16_t b;
    };
    
};

union Byte2Data
{
    char buff[2];
    int16_t int16_value;
    uint16_t uint16_value;
};

#define MSG_VALUE_SET(jsonObject, name, type, value) \
    do                                               \
    {                                                \
        jsonObject[name][0] = type;                  \
        jsonObject[name][1] = value;                 \
    } while (0)

#define JSON_TRY_GET_VALUE(jsonObject, name, type, defaultValue) \
    (jsonObject.find(name) != jsonObject.end()) ? jsonObject[name].get<type>() : defaultValue


#define GET_ARRAY_LEN(x) (sizeof(x) / sizeof(x[0]))


namespace Utils
{
    /***********************************************************************************************************
     * @brief 生成一条Guid字符串，例如: bd44dcf4-abc1-1923-9040-d1fd19416165
    ***********************************************************************************************************/
    std::string GetNewUUID();



    /***********************************************************************************************************
     * @brief 读取文本文件的内容
     * @param path 文件位置
     * @param outStr 存储字符串的对象
     * @return true: 读取成功 | false: 读取失败
    ***********************************************************************************************************/
    bool LoadTextFile(const std::string &path, std::string &outStr);



    /***********************************************************************************************************
     * @brief 保存文本到文件
     * @param path 文件位置
     * @param inStr 内容
     * @return true: 保存成功 | false: 保存失败
    ***********************************************************************************************************/
    bool SaveTextFile(const std::string &path, const std::string &inStr);



    /***********************************************************************************************************
     * @brief 解压数据，注：这里用的不是标准的zlib格式，解压zlib数据时需要掐头(2字节)去尾(4字节)
     * @param comBuf 压缩的数据
     * @param comSize 压缩的数据大小
     * @param buffer 用于存储解压出来的数据
     * @param bufferSize 解压缓存的大小
     * @return 解压出来的数据大小，0表示失败
    ***********************************************************************************************************/
    uint32_t RawInflateDecompresse(const void *comBuf, uint32_t comSize, void *buffer, uint32_t bufferSize);




    /***********************************************************************************************************
     * @brief 压缩数据，注：这里用的不是标准的zlib格，无法使用标准的zlib解压
     * @param uncomBuf 要进行压缩的数据
     * @param uncomSize 要进行压缩的数据的大小
     * @param buffer 用于存储压缩数据
     * @param bufferSize 压缩缓存的大小
     * @return 压缩出来的数据大小，0表示失败
    ***********************************************************************************************************/
    uint32_t RawDeflateCompresse(const void *uncomBuf, uint32_t uncomSize, void *buffer, uint32_t bufferSize);


    /***********************************************************************************************************
     * @brief 切割字符串
     * @param str 要切割的字符串
     * @param pattern 分个参数，例如:";"
     * @param res 存储容器
    ***********************************************************************************************************/
    void StringSplit(const std::string &str, const std::string &pattern, std::vector<std::string> &res);



    /***********************************************************************************************************
     * @brief   切割字符串，使用std::list相对与std::vector来说，在添加新内容的时候不会出现存储空间不够而重新分配导致的数据拷贝，
     *          但是却需要花费更多的内存来存储，而且遍历的时候也会比std::vector慢
     * @param str 要切割的字符串
     * @param pattern 分个参数，例如:";"
     * @param res 存储容器
    ***********************************************************************************************************/
    void StringSplit(const std::string &str, const std::string &pattern, std::list<std::string> &res);



    /***********************************************************************************************************
     * @brief 替换字符串中对应的子字符串
     * @param str 要进行替换的字符串
     * @param oldValue 要替换的子字符串
     * @param newValue 替换成的字符串
     * @return 替换好的字符串
    ***********************************************************************************************************/
    std::string StringReplace(const std::string &str, const std::string& oldValue, const std::string& newValue);



    /***********************************************************************************************************
     * @brief 十六进制数据转字符串形式
     * @param ptr 十六进制数据
     * @param length 数据长度
     * @return 字符串
    ***********************************************************************************************************/
    std::string ToHexString(const void* ptr, int32_t length);



    /***********************************************************************************************************
     * @brief 十六进制字符串转数组，例如:"AABb"这个字符串,将转成数组 [0]=0xAA, [1]=0xBB
     * @param str 对应十六进制字符的字符串(由'0'~'9'和'a'~'f'和'A'~'F'构成)
     * @param buff 用于存储转换出来的十六进制数据的缓存
     * @param buffSize 缓存大小
     * @return true 转换成功， false 转换失败
    ***********************************************************************************************************/
    bool StringToHex(const std::string& str, void * buff, uint32_t buffSize);
    


    
    template<typename T>
    inline void GetJsonValue(const nlohmann::json& json, T& outValue, const std::string& keyName,const T &defaultValue)
    {
        auto it = json.find(keyName);
        if(it != json.end())
        {
            outValue = it->get<T>();
        }
        else
        {
            outValue = defaultValue;
        }
    }
}

#endif